﻿#ifndef __AVOID_BW_CONTROL_COLOR_DEFINE_HEAD_FILE_INCLUDED__
#define __AVOID_BW_CONTROL_COLOR_DEFINE_HEAD_FILE_INCLUDED__
#include <memory>
#include <utility>
#include <typeinfo>
#include <type_traits>

namespace swui
{
	/*  颜色类型
		*  若ColorFormat为rgba则为 AARRGGBB
		*  若ColorFormat为rgb则为   ffRRGGBB
		*/
	typedef unsigned ctlColor;
	//基本颜色对
	class ctlDoubleColor
	{
	public:
		ctlColor crBegin, crEnd;
		ctlDoubleColor(ctlColor begin = 0, ctlColor end = 0)
			: crBegin(begin), crEnd(end) {}
		void set(ctlColor begin, ctlColor end) {
			crBegin = begin, crEnd = end;
		}
		void swap() {
			std::swap(crBegin, crEnd);
		}
	};
	template<typename Type>
	class ctlQuadColor
	{
	public:
		Type leave, stay, down, disenable;
		ctlQuadColor(Type Leave = 0, Type Stay = 0, Type Down = 0, Type Disenable = 0)
			: leave(Leave), stay(Stay), down(Down), disenable(Disenable) {}
	}; 
	//平滑过渡数据类型
	class ctlSmoothTransform
	{
	public:
		static const int maxValue = 1000;
		static const int minValue = 0;
	public:
		/* 鼠标进入和离开的过渡
		 * 如果当前鼠标停留在控件上，那么认为是进入过渡，将减少 enterLeave 直至 minValue
		 * 如果当前鼠标不在控件上，那么认为是退出过渡，将增加 enterLeave 直至 maxValue
		 * 当前颜色（鼠标状态为 leave 或 stay 且不为 down）*/
		int enterLeave;
	};
	//样式结构的类型
	enum class ctlStyleType : unsigned {
		gradient, solid, edit, progress, list
	};
	//色彩格式
	enum class ctlColorFormat : unsigned {
		rgba, rgb
	};
	//额外的线
	struct ctlExtraLine
	{
		bool withLine;
		ctlColor color;	// 32 位颜色
		unsigned pos;
		ctlExtraLine() : withLine(false), color(0), pos(0) {}
	};
	//基本样式结构
	class ctlStyleBase
	{
	public:
		ctlColorFormat colorFormat;
		ctlStyleType styleType;
	public:
		bool isColor32() { return colorFormat == ctlColorFormat::rgba; }
		bool isColor24() { return colorFormat == ctlColorFormat::rgb; }
	public:
		virtual ~ctlStyleBase() {};
		virtual ctlStyleBase* clone()const = 0;	//返回new出来的指针，记得delete
	};

	/*
		* 基本单色样式
		* 若没有选中状态的控件，同下面 ctlStyleGradient 
		* 可用于 ctlButton、ctlCheckBox、ctlRadioBox、ctlScroll
		*/
	class ctlStyleSolid : public ctlStyleBase
	{
	public:
		static const ctlStyleType uniqueType = ctlStyleType::solid;
	public:
		typedef enum {
			common, 
			black
		} _subType;
		_subType subStyle;
		ctlQuadColor<ctlColor> text, selectText;	//文字颜色、选中状态文字颜色
		ctlQuadColor<ctlColor> fill, border;				//填充颜色、边框颜色
		ctlQuadColor<ctlColor> selectFill, selectBorder;	  //选中状态填充颜色、边框颜色
		ctlColor crSelectedFlag, crDisenabledSelectedFlag;		//选中标志的颜色	
		ctlSmoothTransform smooth;			//过渡信息（若没必要，最好别自行修改）
		ctlExtraLine horizontalLine;
	public:
		ctlStyleSolid& changeToSelect()
		{
			selectBorder.leave = border.leave;
			selectBorder.stay = border.stay;
			selectFill.leave = fill.leave;
			selectFill.stay = fill.stay;
			return *this;
		}
	public:
		ctlStyleSolid(_subType subType = common, 
			ctlColorFormat type = ctlColorFormat::rgb) 
		{
			colorFormat = type;
			styleType = ctlStyleType::solid;
			set(subType);
		}
		void set(_subType subType);
		virtual ~ctlStyleSolid() {}
		virtual ctlStyleBase* clone()const {
			return new ctlStyleSolid(*this);
		}
	};

	/*
		* 基本渐变样式
		* 若没有选中状态的控件
		* 则sf...、sb...、crSelectedFlag及crDisenabledSelectedFlag成员无用
		* 可用于 ctlButton、ctlCheckBox、ctlRadioBox、ctlScroll
		*/
	class ctlStyleGradient : public ctlStyleBase
	{
	public:
		static const ctlStyleType uniqueType = ctlStyleType::gradient;
	public:
		/*
		 * 含有 select 前缀的样式表示在选中后的配色类似于按下按钮
		 * 含有 scroll 前缀的样式用于滚动条
		 * 其余的样式表示在选中后的配色类似于正常情况
		 */
		typedef enum : unsigned {
			common, blue = common, 
			orange, purple, yellow, green
		} _subType;
		_subType subStyle;
		typedef enum {
			vertical, horizontal,
			reverse_vertical, 
			reverse_horizontal
		} ctlGradientDirection;
		ctlQuadColor<ctlColor> text, selectText;		//文字颜色、选中状态文字颜色
		ctlQuadColor<ctlDoubleColor> fill, border;				//填充颜色、边框颜色
		ctlQuadColor<ctlDoubleColor> selectFill, selectBorder;	  //选中状态填充颜色、边框颜色
		ctlColor crSelectedFlag, crDisenabledSelectedFlag;		//选中标志的颜色	
		ctlGradientDirection gradientDirection;		//渐变方向（x 或 y）
		ctlSmoothTransform smooth;			//过渡信息（若没必要，最好别自行修改）
		ctlExtraLine horizontalLine;
	public:
		//让特定状态的颜色渐变方向相反
		ctlStyleGradient& swapFillDirection();
		ctlStyleGradient& swapBorderDirection();
		ctlStyleGradient& swapStayFillDirection();
		ctlStyleGradient& swapStayBorderDirection();
	public:
		ctlStyleGradient& changeToSelect()
		{
			selectBorder.leave = border.leave;
			selectBorder.stay = border.stay;
			selectFill.leave = fill.leave;
			selectFill.stay = fill.stay;
			return *this;
		}
		ctlStyleGradient& changeToScroll()
		{
			fill.stay = fill.down = fill.leave;
			border.stay = border.down = border.leave;
			return *this;
		}
		ctlStyleGradient& changeToCommon()
		{
			selectFill.stay = fill.down;
			border.stay = border.down;
			selectFill.down = fill.down;
			selectBorder.down = border.down;
			selectBorder.stay = border.stay;
			selectBorder.leave = border.down;
			selectFill.leave = fill.down;
			return *this;
		}
		ctlStyleGradient& changeStayAsDown()
		{
			selectFill.stay = selectFill.down;
			selectBorder.stay = selectBorder.down;
			fill.stay = fill.down;
			border.stay = border.down;
			return *this;
		}
	public:
		ctlStyleGradient(_subType subType = common, 
			ctlGradientDirection gradir = vertical, 
			ctlColorFormat type = ctlColorFormat::rgb);
		void set(_subType subType);
		virtual ~ctlStyleGradient() {}
		virtual ctlStyleBase* clone()const {
			return new ctlStyleGradient(*this);
		}
	};

	/*
	 * 文本框样式
	 * 可用于 ctlEdit、ctlSingleEdit
	 * ctlSingleEdit 暂不支持透明
	 * ctlEdit selectBar 和 textSelected 同时拥有透明度有可能造成错误
	 */
	class ctlStyleEdit : public ctlStyleBase
	{
	public:
		static const ctlStyleType uniqueType = ctlStyleType::edit;
	public:
		typedef enum {
			common
		} _subType;
		_subType subStyle;
		ctlColor textLeave, textSelected, textDisenable;		//文字颜色
		ctlColor selectBar;			//选中的颜色
		ctlColor caret;				//插入符的颜色
	public:
		ctlStyleEdit(_subType subType = common, 
			ctlColorFormat type = ctlColorFormat::rgb) 
		{ 
			colorFormat = type;
			styleType = ctlStyleType::edit;
			set(subType);
		}
		void set(_subType subType);
		virtual ~ctlStyleEdit() {}
		virtual ctlStyleBase* clone()const {
			return new ctlStyleEdit(*this);
		}
	};
	
	class ctlStyleProgress : public ctlStyleBase
	{
	public:
		static const ctlStyleType uniqueType = ctlStyleType::progress;
	public:
		typedef enum {
			common, orange
		} _subType;
		_subType subStyle;
		ctlDoubleColor bkBorder, bkFill, fill, border;
	public:
		ctlStyleProgress(_subType subType = common, 
			ctlColorFormat type = ctlColorFormat::rgb) 
		{ 
			colorFormat = type;
			styleType = ctlStyleType::progress;
			set(subType);
		}
		ctlStyleProgress& changeToCommon()
		{
			fill = bkFill;
			border = bkBorder;
			return *this;
		}
	public:
		void set(_subType subType);
		virtual ~ctlStyleProgress() {}
		virtual ctlStyleBase* clone()const {
			return new ctlStyleProgress(*this);
		}
	};
	class ctlStyleList : public ctlStyleBase
	{
	public:
		static const ctlStyleType uniqueType = ctlStyleType::list;
	public:
		typedef enum {
			common, gcommon, lgcommon,
			orange, gorange, lgorange
		} _subType;
		_subType subStyle;
		ctlDoubleColor selectFill;
		ctlColor selectTextColor, textColor;
	public:
		ctlStyleList(_subType subType = common, 
			ctlColorFormat type = ctlColorFormat::rgb) 
		{ 
			colorFormat = type;
			styleType = ctlStyleType::list;
			set(subType);
		}
	public:
		void set(_subType subType);
		virtual ~ctlStyleList() {}
		virtual ctlStyleBase* clone()const {
			return new ctlStyleList(*this);
		}
	};

	template<typename CastTo> inline
	CastTo style_cast(const ctlStyleBase* style)
	{
		static_assert(std::is_pointer<CastTo>::value,
			"CastTo 不是指针无法转换");
		typedef typename std::remove_pointer<CastTo>::type no_pointer;
		typedef typename std::remove_const<no_pointer>::type common_type;
		if(style == nullptr) return nullptr;
		if(style->styleType == common_type::uniqueType)
			return static_cast<CastTo>(style);
		return nullptr;
	}
	template<typename CastTo> inline
	const CastTo& style_cast(const ctlStyleBase& style)
	{
		typedef typename std::remove_reference<CastTo>::type *pointer;
		pointer ptr = style_cast<pointer>(&style);
		if(ptr != nullptr) return *ptr;
		throw std::bad_cast();
	}
	template<typename CastTo> inline
	CastTo style_cast(ctlStyleBase* style)
	{
		static_assert(std::is_pointer<CastTo>::value,
			"CastTo 不是指针无法转换");
		typedef typename std::remove_pointer<CastTo>::type no_pointer;
		typedef typename std::add_const<no_pointer>::type common_type;
		return const_cast<CastTo>(
			style_cast<common_type*>(
			static_cast<common_type*>(style)));
	}
	template<typename CastTo> inline
	CastTo& style_cast(ctlStyleBase& style)
	{
		typedef typename std::remove_reference<CastTo>::type *pointer;
		pointer ptr = style_cast<pointer>(&style);
		if(ptr != nullptr) return *ptr;
		throw std::bad_cast();
	}
} //namespace swui

#endif